const fs = require("fs");
const { UPLOAD } = require("../config/config.default");
const { User, Subscribe } = require("../model");
const { generateToken } = require("../utils/jwt");
const { storeImg } = require("./uploadController");
const { pick } = require("lodash");

const userFields = ["username", "avatar", "_id", "subscribeCount", "fansCount"];

// 注册
exports.register = async (req, res) => {
  const { username, email, phone } = req.body;
  const uniqueCondition = [];
  username && uniqueCondition.push({ username });
  email && uniqueCondition.push({ email });
  phone && uniqueCondition.push({ phone });
  const existUser = await User.find({
    $or: uniqueCondition,
  });
  if (existUser.length) {
    return res.send(400, "用户名或手机号或邮箱已注册");
  }
  const user = new User(req.body);
  user.save();
  res.send("注册成功");
};

// 登录
exports.login = async (req, res) => {
  const existUser = await User.findOne(req.body);
  if (!existUser) {
    return res.send(400, "账号或密码错误");
  }
  res.send(200, {
    userInfo: existUser,
    token: generateToken(existUser.toJSON()),
  });
};

// 用户详情
exports.getById = async (req, res) => {
  const id = req.params.id;
  const user = await User.findById(id);

  const userId = req.user?._id;
  let isSubscribe = false;
  if (userId && id !== userId) {
    isSubscribe = !!(await Subscribe.findOne({
      user: userId,
      channel: id,
    }));
  }

  res.send({
    data: {
      ...pick(user, userFields),
      isSubscribe,
    },
  });
};

// 用户头像更换
exports.updateAvatar = async (req, res) => {
  const fileDir = UPLOAD.avatar.dir;
  let path;
  try {
    const { filePath } = await storeImg(fileDir)(req);
    path = filePath;
    const id = req.user._id;
    const user = await User.findById(id);
    user.avatar = filePath;
    user.save();
    res.status(200).json({
      message: "更换成功",
      avatarPath: filePath,
    });
  } catch (error) {
    path && fs.rmSync(path);
    res.status(400).json({
      error,
    });
  }
};

// 修改个人信息
exports.update = async (req, res) => {
  await User.findByIdAndUpdate(
    req.user._id,
    {
      $set: req.body,
    },
    { new: false }
  ); // 注意格式 new为true返回修改后的信息 false则返回修改前的信息
  res.send(200, "修改成功");
};

// 关注频道(某个人)
exports.subscribe = async (req, res) => {
  const subscribeId = req.params.subscribeId;
  const userId = req.user._id;
  if (userId === subscribeId) {
    return res.send(400, "不能关注自己");
  }
  const existSubscribe = await Subscribe.findOne({
    user: userId,
    channel: subscribeId,
  });
  if (existSubscribe) {
    return res.send(400, "已经关注过了");
  }
  await new Subscribe({
    user: userId,
    channel: subscribeId,
  }).save();
  const channel = await User.findById(subscribeId);
  channel.fansCount++;
  await channel.save();

  const user = await User.findById(userId);
  user.subscribeCount++;
  await user.save();
  res.send(200, "关注成功");
};

// 取消关注频道(某个人)
exports.unsubscribe = async (req, res) => {
  const subscribeId = req.params.subscribeId;
  const userId = req.user._id;
  if (userId === subscribeId) {
    return res.send(400, "不能取消关注自己");
  }
  const existSubscribe = await Subscribe.findOne({
    user: userId,
    channel: subscribeId,
  });
  if (!existSubscribe) {
    return res.send(400, "没有关注");
  }
  //   await existSubscribe.remove(); remove已移除
  await Subscribe.deleteOne({ user: userId, channel: subscribeId });

  const channel = await User.findById(subscribeId);
  channel.fansCount--;
  await channel.save();

  const user = await User.findById(userId);
  user.subscribeCount--;
  await user.save();
  res.send(200, "取消关注成功");
};

// 关注某用户的列表
exports.getSubscribers = async (req, res) => {
  const userId = req.params.userId;
  const list = await Subscribe.find({
    channel: userId,
  }).populate("user"); // populate 第一个参数为关联字段
  res.send(
    200,
    list.map((sub) => {
      return pick(sub.user, userFields);
    })
  );
};

// 某用户的关注列表
exports.getChannels = async (req, res) => {
  const userId = req.params.userId;
  const list = await Subscribe.find({
    user: userId,
  }).populate("channel");
  res.send(
    200,
    list.map((sub) => {
      return pick(sub.channel, userFields);
    })
  );
};
